package com.dragon.english_practice_back.service.impl;

import com.dragon.english_practice_back.entity.AIJson.TranslateQuestion;
import com.dragon.english_practice_back.entity.Translate;
import com.dragon.english_practice_back.enums.TranslateQuestionType;
import com.dragon.english_practice_back.service.AuthenticationUtil;
import com.dragon.english_practice_back.service.ExerciseService;
import com.dragon.english_practice_back.service.GenerateExerciseService;
import com.dragon.english_practice_back.enums.RedisPrefixEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@EnableScheduling
public class ExerciseServiceImpl implements ExerciseService {
    @Value("${translate.exercise.refill-threshold:5}")
    private Integer REFILL_THRESHOLD;

    private final RedisTemplate<String, TranslateQuestion> redisTemplate;
    private final AuthenticationUtil authenticationUtil;
    private final GenerateExerciseService generateExerciseService;

    public ExerciseServiceImpl(RedisTemplate<String, TranslateQuestion> redisTemplate, AuthenticationUtil authenticationUtil, GenerateExerciseService generateExerciseService) {
        this.redisTemplate = redisTemplate;
        this.authenticationUtil = authenticationUtil;
        this.generateExerciseService = generateExerciseService;
    }

    @Override
    public TranslateQuestion getOneQuestion(TranslateQuestionType type) {
        // 从redis中获取题目
        TranslateQuestion question = getQuestionFromRedis(type);
        // 检查剩余数量并异步补充
        checkAndRefillQuestions(type);

        return question;
    }

    // 从redis中获取题目
    private TranslateQuestion getQuestionFromRedis(TranslateQuestionType type) {
        TranslateQuestion question = null;
        // 判断type
        if (type == TranslateQuestionType.English_Chinese_Translation) {// 从队列获取题目
            question = redisTemplate.opsForList().leftPop(RedisPrefixEnum.ENGLISH_CHINESE_TRANSLATE_QUEUE.getPrefix() + authenticationUtil.id());
        }
        else if (type == TranslateQuestionType.Chinese_English_Translation) {
            question = redisTemplate.opsForList().leftPop(RedisPrefixEnum.CHINESE_ENGLISH_TRANSLATE_QUEUE.getPrefix() + authenticationUtil.id());
        }

        return question;
    }

    // 检查剩余数量并异步补充
    private void checkAndRefillQuestions(TranslateQuestionType type) {
        Long remaining = 10L;
        // 判断type
        if (type == TranslateQuestionType.English_Chinese_Translation) {
            remaining = redisTemplate.opsForList().size(RedisPrefixEnum.ENGLISH_CHINESE_TRANSLATE_QUEUE.getPrefix() + authenticationUtil.id());
            log.info("userId: {} ECT remaining: {}", authenticationUtil.id(), remaining);
        }
        else if (type == TranslateQuestionType.Chinese_English_Translation) {
            remaining = redisTemplate.opsForList().size(RedisPrefixEnum.CHINESE_ENGLISH_TRANSLATE_QUEUE.getPrefix() + authenticationUtil.id());
            log.info("userId: {} CET remaining: {}", authenticationUtil.id(), remaining);
        }

        if (remaining < REFILL_THRESHOLD) {
            log.info("invoke asyncRefillQuestions");
            generateExerciseService.asyncRefillQuestions(authenticationUtil.id(), type);
        }
    }

    // 每天0点清空队列
    @Scheduled(cron = "0 0 0 * * ?")
    public void discardOldQuestions() {
        log.info("执行定时任务:删除所有用户的翻译题目队列所有题目");
        // 清空所有以前缀QUEUE_KEY_PREFIX开头的队列
        // todo 这里删除题目队列没有使用锁，因为从GPT获取题目需要20秒左右的时间，在接近0点请求生成的题目可能会在0点后被加入队列，但这些题目的个性化元素是前一天的
        redisTemplate.keys(RedisPrefixEnum.ENGLISH_CHINESE_TRANSLATE_QUEUE.getPrefix() + "*").forEach(redisTemplate::delete);
        redisTemplate.keys(RedisPrefixEnum.CHINESE_ENGLISH_TRANSLATE_QUEUE.getPrefix() + "*").forEach(redisTemplate::delete);
    }

    @Override
    public boolean checkAnswer(Translate answer) {
        //todo
        return false;
    }

}
